home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / faq-s.zip / PIBASYN1.MOD < prev    next >
Text File  |  1991-05-04  |  51KB  |  856 lines

  1. (*----------------------------------------------------------------------*)
  2. (*                BIOS_RS232_Init --- Initialize UART                   *)
  3. (*----------------------------------------------------------------------*)
  4.  
  5. PROCEDURE BIOS_RS232_Init( ComPort : INTEGER; ComParm : WORD );
  6.  
  7. (*----------------------------------------------------------------------*)
  8. (*                                                                      *)
  9. (*     Procedure:  BIOS_RS232_Init                                      *)
  10. (*                                                                      *)
  11. (*     Purpose:    Issues interrupt $14 to initialize the UART          *)
  12. (*                                                                      *)
  13. (*     Calling Sequence:                                                *)
  14. (*                                                                      *)
  15. (*        BIOS_RS232_Init( ComPort, ComParm : INTEGER );                *)
  16. (*                                                                      *)
  17. (*           ComPort  --- Communications Port Number (0 thru 3)         *)
  18. (*           ComParm  --- Communications Parameter Word                 *)
  19. (*                                                                      *)
  20. (*      Calls:   INTR   (to perform BIOS interrupt $14)                 *)
  21. (*                                                                      *)
  22. (*----------------------------------------------------------------------*)
  23.  
  24. VAR
  25.    Regs: Registers;
  26.  
  27. BEGIN   (* BIOS_RS232_Init *)
  28.                                    (* Initialize port    *)
  29.    WITH Regs DO
  30.       BEGIN
  31.          Ax := ComParm AND $00FF;  (* AH=0; AL=ComParm   *)
  32.          Dx := ComPort;            (* Port number to use *)
  33.          INTR($14, Regs);
  34.       END;
  35.  
  36. END    (* BIOS_RS232_Init *);
  37.  
  38. (*----------------------------------------------------------------------*)
  39. (*               Async_Isr --- Interrupt Service Routine                *)
  40. (*----------------------------------------------------------------------*)
  41.  
  42. PROCEDURE Async_Isr( Flags, CS, IP, AX, BX, CX, DX, SI, DI, DS, ES, BP : WORD );
  43.    Interrupt;
  44.  
  45. (*----------------------------------------------------------------------*)
  46. (*                                                                      *)
  47. (*     Procedure:  Async_Isr                                            *)
  48. (*                                                                      *)
  49. (*     Purpose:    Invoked when serial port interrupt occurs.           *)
  50. (*                                                                      *)
  51. (*     Calling Sequence:                                                *)
  52. (*                                                                      *)
  53. (*        Async_Isr;                                                    *)
  54. (*                                                                      *)
  55. (*           --- Called asynchronously only!!!!!!                       *)
  56. (*                                                                      *)
  57. (*----------------------------------------------------------------------*)
  58.  
  59. BEGIN   (* Async_Isr *)
  60.  
  61. INLINE(
  62.   $FB/                                 {         STI                                ;Allow interrupts}
  63.                                        {;}
  64.                                        {;  Begin major polling loop over pending interrupts.}
  65.                                        {;}
  66.                                        {;  The polling loop is needed because the 8259 cannot handle another 8250}
  67.                                        {;  interrupt while we service this interrupt.  We keep polling here as long}
  68.                                        {;  as an interrupt is received.}
  69.                                        {;}
  70.   $8B/$16/>ASYNC_UART_IIR/             {Poll:    MOV     DX,[>Async_Uart_IIR]       ;Get Interrupt ident register}
  71.   $EC/                                 {         IN      AL,DX                      ;Pick up interrupt type}
  72.                                        {;}
  73.   $A8/$01/                             {         TEST    AL,1                       ;See if any interrupt signalled.}
  74.   $74/$03/                             {         JZ      Polla                      ;Yes --- continue}
  75.   $E9/$D4/$01/                         {         JMP     NEAR Back                  ;No  ---  return to invoker}
  76.                                        {;}
  77.                                        {;  Determine type of interrupt.}
  78.                                        {;  Possibilities:}
  79.                                        {;}
  80.                                        {;     0 = Modem status changed}
  81.                                        {;     2 = Transmit hold register empty (write char)}
  82.                                        {;     4 = Character received from port}
  83.                                        {;     6 = Line status changed}
  84.                                        {;}
  85.   $24/$06/                             {Polla:   AND     AL,6                       ;Strip unwanted bits from interrupt type}
  86.   $3C/$04/                             {         CMP     AL,4                       ;Check if interrupt >= 4}
  87.   $74/$03/                             {         JE      Pollb                      ;}
  88.   $E9/$F6/$00/                         {         JMP     NEAR Int2}
  89.                                        {;}
  90.                                        {;  Write interrupts must be turned on if a higher-priority interrupt}
  91.                                        {;  has been received, else the characters may not be sent (and a lockup}
  92.                                        {;  may occur).}
  93.                                        {;}
  94.   $50/                                 {Pollb:   PUSH    AX                         ;Save interrupt type}
  95.   $E8/$BA/$01/                         {         CALL    EnabWI                     ;Enable write interrupts}
  96.   $58/                                 {         POP     AX                         ;Restore interrupt type}
  97.                                        {;}
  98.                                        {;  --- Received a character ----}
  99.                                        {;}
  100.   $3C/$04/                             {Int4:    CMP     AL,4                       ;Check for received char interrupt}
  101.   $74/$03/                             {         JE      Int4a                      ;Yes -- process it.}
  102.   $E9/$EA/$00/                         {         JMP     NEAR Int2                  ;No -- skip.}
  103.                                        {;}
  104.                                        {;  Read the character from the serial port.}
  105.                                        {;}
  106.   $8B/$16/>ASYNC_BASE/                 {Int4a:   MOV     DX,[>Async_Base]           ;Read character from port}
  107.   $EC/                                 {         IN      AL,DX}
  108.                                        {;}
  109.                                        {;  Check if spurious character rejection mode is active.  If so, check}
  110.                                        {;  the LSR for any error which occurred on this character.  If any}
  111.                                        {;  occurred, replace the character with the "noise filter" character.}
  112.                                        {;}
  113.   $F6/$06/>ASYNC_REJECT_NOISE/$01/     {         TEST    BYTE [<Async_Reject_Noise],1  ;See if we're rejecting noise}
  114.   $74/$0F/                             {         JZ      Int4a1}
  115.                                        {;}
  116.   $F6/$06/>ASYNC_LINE_STATUS/$1C/      {         TEST    BYTE [<Async_Line_Status],$1C ;See if LSR signalled error}
  117.   $74/$08/                             {         JZ      Int4a1                        ;No -- character must be OK}
  118.   $A0/>ASYNC_NOISE_CHAR/               {         MOV     AL,[>Async_Noise_Char]        ;Else use "noise" character}
  119.   $80/$26/>ASYNC_LINE_STATUS/$02/      {         AND     BYTE [<Async_Line_Status],$02 ;Clear LSR status flags}
  120.                                        {;}
  121.                                        {;  Check if XON/XOFF honored.  If so, check if incoming character is}
  122.                                        {;  an XON or an XOFF.}
  123.                                        {;}
  124.   $F6/$06/>ASYNC_DO_XONXOFF/$01/       {Int4a1:  TEST    BYTE [<Async_Do_XonXoff],1 ;See if we honor XON/XOFF}
  125.   $74/$25/                             {         JZ      Int4d                      ;No -- skip XON/XOFF checks}
  126.                                        {;}
  127.   $3C/<XON/                            {         CMP     AL,<XON                    ;See if XON found}
  128.   $74/$11/                             {         JE      Int4b                      ;Skip if XON found}
  129.   $3C/<XOFF/                           {         CMP     AL,<XOFF                   ;See if XOFF found}
  130.   $75/$1D/                             {         JNE     Int4d                      ;Skip if XOFF not found}
  131.                                        {;}
  132.                                        {;  XOFF received -- set flag indicating sending of chars isn't possible}
  133.                                        {;}
  134.   $C6/$06/>ASYNC_XOFF_RECEIVED/$01/    {         MOV     BYTE [<Async_XOFF_Received],1    ;Turn on received XOFF flag}
  135.   $C6/$06/>ASYNC_XOFF_REC_DISPLAY/$01/ {         MOV     BYTE [<Async_XOFF_Rec_Display],1 ;Turn on display flag}
  136.   $E9/$A8/$FF/                         {         JMP     NEAR Poll}
  137.                                        {;}
  138.                                        {;  XON received -- allow more characters to be sent.}
  139.                                        {;}
  140.   $C6/$06/>ASYNC_XOFF_RECEIVED/$00/    {Int4b:   MOV     BYTE [<Async_XOFF_Received],0   ;Turn off received XOFF flag}
  141.   $C6/$06/>ASYNC_XON_REC_DISPLAY/$01/  {         MOV     BYTE [<Async_XON_Rec_Display],1 ;Turn on display flag}
  142.                                        {;}
  143.   $E8/$6E/$01/                         {         CALL    EnabWI                          ;Enable write interrupts}
  144.   $E9/$A0/$00/                         {         JMP     NEAR Int4z}
  145.                                        {;}
  146.                                        {;  Not XON/XOFF -- handle other character.}
  147.                                        {;}
  148.   $F6/$06/>ASYNC_LINE_STATUS/$02/      {Int4d:   TEST    BYTE [>Async_Line_Status],2 ;Check for buffer overrun}
  149.   $74/$03/                             {         JZ      Int4e                       ;Yes --- don't store anything}
  150.   $E9/$96/$00/                         {         JMP     Int4z}
  151.                                        {;}
  152.   $8B/$1E/>ASYNC_BUFFER_HEAD/          {Int4e:   MOV     BX,[>Async_Buffer_Head]    ;Current position in input buffer}
  153.   $C4/$3E/>ASYNC_BUFFER_PTR/           {         LES     DI,[>Async_Buffer_Ptr]     ;Pick up buffer address}
  154.   $01/$DF/                             {         ADD     DI,BX                      ;Update position}
  155.   $26/$88/$05/                         {     ES: MOV     [DI],AL                    ;Store received character in buffer}
  156.   $FF/$06/>ASYNC_BUFFER_USED/          {         INC     WORD [>Async_Buffer_Used]  ;Increment count of chars in buffer}
  157.                                        {;}
  158.   $A1/>ASYNC_BUFFER_USED/              {         MOV     AX,[>Async_Buffer_Used]    ;Pick up buffer usage count}
  159.   $3B/$06/>ASYNC_MAXBUFFERUSED/        {         CMP     AX,[>Async_MaxBufferUsed]  ;See if greater usage than ever before}
  160.   $7E/$03/                             {         JLE     Int4f                      ;Skip if not}
  161.   $A3/>ASYNC_MAXBUFFERUSED/            {         MOV     [>Async_MaxBufferUsed],AX  ;This is greatest use thus far}
  162.                                        {;}
  163.   $43/                                 {Int4f:   INC     BX                         ;Increment buffer pointer}
  164.   $3B/$1E/>ASYNC_BUFFER_SIZE/          {         CMP     BX,[>Async_Buffer_Size]    ;Check if past end of buffer}
  165.   $7E/$02/                             {         JLE     Int4h}
  166.   $31/$DB/                             {         XOR     BX,BX                      ;If so, wrap around to front}
  167.                                        {;}
  168.   $39/$1E/>ASYNC_BUFFER_TAIL/          {Int4h:   CMP     WORD [>Async_Buffer_Tail],BX ;Check for overflow}
  169.   $74/$60/                             {         JE      Int4s                        ;Jump if head ran into tail}
  170.                                        {;}
  171.   $89/$1E/>ASYNC_BUFFER_HEAD/          {         MOV     [>Async_Buffer_Head],BX    ;Update head pointer}
  172.                                        {;}
  173.                                        {;  Check for receive buffer nearly full here.}
  174.                                        {;}
  175.                                        {;  If XON/XOFF available, and buffer getting full, set up to send}
  176.                                        {;  XOFF to remote system.}
  177.                                        {;}
  178.                                        {;  This happens in two possible stages:}
  179.                                        {;}
  180.                                        {;     (1)  An XOFF is sent right when the buffer becomes 'Async_Buffer_High'}
  181.                                        {;          characters full.}
  182.                                        {;}
  183.                                        {;     (2)  A second XOFF is sent right when the buffer becomes}
  184.                                        {;          'Async_Buffer_High_2' characters full;  this case is likely the}
  185.                                        {;          result of the remote not having seen our XOFF because it was}
  186.                                        {;          lost in transmission.}
  187.                                        {;}
  188.                                        {;  If CTS/RTS handshaking, then drop RTS here if buffer nearly full.}
  189.                                        {;  Note that this has to be done even if the XOFF is being sent as well.}
  190.                                        {;}
  191.                                        {;}
  192.                                        {;  Check receive buffer size against first high-water mark.}
  193.                                        {;}
  194.   $3B/$06/>ASYNC_BUFFER_HIGH/          {         CMP     AX,[>Async_Buffer_High]    ;AX still has Async_Buffer_Used}
  195.   $7C/$60/                             {         JL      Int4z                      ;Not very full, so keep going.}
  196.                                        {;}
  197.                                        {;  Remember if we've already (supposedly) disabled sender.}
  198.                                        {;}
  199.   $8A/$16/>ASYNC_SENDER_ON/            {         MOV     DL,[<Async_Sender_On]      ;Get sender enabled flag.}
  200.                                        {;}
  201.                                        {;  Drop through means receive buffer getting full.}
  202.                                        {;  Check for XON/XOFF.}
  203.                                        {;}
  204.   $F6/$06/>ASYNC_OV_XONXOFF/$01/       {         TEST    BYTE [<Async_OV_XonXoff],1 ;See if we honor XON/XOFF}
  205.                                        {;                                           ; for buffer overflow}
  206.   $74/$1A/                             {         JZ      Int4k                      ;No -- skip XON/XOFF checks}
  207.                                        {;}
  208.                                        {;  Check if we've already sent XOFF.}
  209.                                        {;}
  210.   $F6/$06/>ASYNC_XOFF_SENT/$01/        {         TEST    BYTE [<Async_XOFF_Sent],1  ;Remember if we sent XOFF or not}
  211.   $74/$06/                             {         JZ      Int4j                      ;No -- go send it now.}
  212.                                        {;}
  213.                                        {;  Check against second high-water mark.}
  214.                                        {;  If we are right at it, send an XOFF regardless of whether we've}
  215.                                        {;  already sent one or not.  (Perhaps the first got lost.)}
  216.                                        {;}
  217.   $3B/$06/>ASYNC_BUFFER_HIGH_2/        {         CMP     AX,[>Async_Buffer_High_2]}
  218.   $75/$0D/                             {         JNE     Int4k                      ;Not at 2nd mark -- skip}
  219.                                        {;}
  220.   $C6/$06/>ASYNC_SEND_XOFF/$01/        {Int4j:   MOV     BYTE [<Async_Send_XOFF],1  ;Indicate we need to send XOFF}
  221.   $E8/$0B/$01/                         {         CALL    EnabWI                     ;Ensure write interrupts enabled}
  222.   $C6/$06/>ASYNC_SENDER_ON/$00/        {         MOV     BYTE [<Async_Sender_On],0  ;Disable sender}
  223.                                        {;}
  224.                                        {;  Check here if we're doing hardware handshakes.}
  225.                                        {;  Drop RTS if CTS/RTS handshaking.}
  226.                                        {;  Drop DTR if DSR/DTR handshaking.}
  227.                                        {;}
  228.   $F6/$C2/$01/                         {Int4k:   TEST    DL,1                       ;See if sender already disabled}
  229.   $74/$36/                             {         JZ      Int4z                      ;Yes -- skip hardware handshakes.}
  230.                                        {;}
  231.   $30/$E4/                             {         XOR     AH,AH                      ;No hardware handshakes}
  232.                                        {;}
  233.   $F6/$06/>ASYNC_DO_CTS/$01/           {         TEST    BYTE [<Async_Do_CTS],1     ;See if RTS/CTS checking}
  234.   $74/$02/                             {         JZ      Int4l                      ;No -- skip it}
  235.                                        {;}
  236.   $B4/<ASYNC_RTS/                      {         MOV     AH,<Async_RTS              ;Turn on RTS bit}
  237.                                        {;}
  238.   $F6/$06/>ASYNC_DO_DSR/$01/           {Int4l:   TEST    BYTE [<Async_Do_DSR],1     ;See if DSR/DTR checking}
  239.   $74/$03/                             {         JZ      Int4m                      ;No -- skip it}
  240.                                        {;}
  241.   $80/$CC/<ASYNC_DTR/                  {         OR      AH,<Async_DTR              ;Turn on DTR bit}
  242.                                        {;}
  243.   $80/$FC/$00/                         {Int4m:   CMP     AH,0                       ;Any hardware signal?}
  244.   $74/$1C/                             {         JZ      Int4z                      ;No -- skip}
  245.                                        {;}
  246.   $8B/$16/>ASYNC_UART_MCR/             {         MOV     DX,[>Async_Uart_MCR]       ;Get modem control register}
  247.   $EC/                                 {         IN      AL,DX}
  248.   $F6/$D4/                             {         NOT     AH                         ;Complement hardware flags}
  249.   $20/$E0/                             {         AND     AL,AH                      ;Nuke RTS/DTR}
  250.   $EE/                                 {         OUT     DX,AL}
  251.                                        {;}
  252.   $C6/$06/>ASYNC_SENDER_ON/$00/        {         MOV     BYTE [<Async_Sender_On],0  ;Indicate sender disabled}
  253.   $E9/$0A/$00/                         {         JMP     Int4z}
  254.                                        {;}
  255.                                        {;  If we come here, then the input buffer has overflowed.}
  256.                                        {;  Characters will be thrown away until the buffer empties at least one slot.}
  257.                                        {;}
  258.   $80/$0E/>ASYNC_LINE_STATUS/$02/      {Int4s:   OR      BYTE [>Async_Line_Status],2     ;Flag overrun}
  259.   $C6/$06/>ASYNC_BUFFER_OVERFLOW/$01/  {         MOV     BYTE [>Async_Buffer_OverFlow],1}
  260.                                        {;}
  261.   $E9/$F5/$FE/                         {Int4z:   JMP     NEAR Poll}
  262.                                        {;}
  263.                                        {;  --- Write a character ---}
  264.                                        {;}
  265.   $3C/$02/                             {Int2:    CMP     AL,2                       ;Check for THRE interrupt}
  266.   $74/$03/                             {         JE      Int2a                      ;Yes -- process it.}
  267.   $E9/$97/$00/                         {         JMP     NEAR Int6                  ;No -- skip.}
  268.                                        {;}
  269.                                        {;  Check first if we need to send an XOFF to remote system.}
  270.                                        {;}
  271.   $F6/$06/>ASYNC_SEND_XOFF/$01/        {Int2a:   TEST    BYTE [<Async_Send_Xoff],1  ;See if we are sending XOFF}
  272.   $74/$34/                             {         JZ      Int2d                      ;No -- skip it}
  273.                                        {;}
  274.                                        {;  Yes, we are to send XOFF to remote.}
  275.                                        {;}
  276.                                        {;  First, check DSR and CTS as requested.}
  277.                                        {;  If those status lines aren't ready, turn off write interrupts and}
  278.                                        {;  try later, after a line status change.}
  279.                                        {;}
  280.   $F6/$06/>ASYNC_DO_DSR/$01/           {         TEST    BYTE [<Async_Do_DSR],1     ;See if DSR checking required}
  281.   $74/$09/                             {         JZ      Int2b                      ;No -- skip it}
  282.                                        {;}
  283.   $8B/$16/>ASYNC_UART_MSR/             {         MOV     DX,[>Async_Uart_MSR]       ;Get modem status register}
  284.   $EC/                                 {         IN      AL,DX}
  285.   $A8/<ASYNC_DSR/                      {         TEST    AL,<Async_DSR              ;Check for Data Set Ready}
  286.   $74/$2E/                             {         JZ      Int2e                      ;If not DSR, turn off write interrupts}
  287.                                        {;}
  288.   $F6/$06/>ASYNC_DO_CTS/$01/           {Int2b:   TEST    BYTE [<Async_Do_CTS],1     ;See if CTS checking required}
  289.   $74/$09/                             {         JZ      Int2c                      ;No -- skip it}
  290.                                        {;}
  291.   $8B/$16/>ASYNC_UART_MSR/             {         MOV     DX,[>Async_Uart_MSR]       ;Get modem status register}
  292.   $EC/                                 {         IN      AL,DX}
  293.   $A8/<ASYNC_CTS/                      {         TEST    AL,<Async_CTS              ;Check for Clear To Send}
  294.   $74/$1E/                             {         JZ      Int2e                      ;If not CTS, turn off write ints}
  295.                                        {;}
  296.                                        {;  All status lines look OK.}
  297.                                        {;  Send the XOFF.}
  298.                                        {;}
  299.   $B0/<XOFF/                           {Int2c:   MOV     AL,<XOFF                   ;Get XOFF Character}
  300.   $8B/$16/>ASYNC_BASE/                 {         MOV     DX,[>Async_Base]           ;Get transmit hold register address}
  301.   $EE/                                 {         OUT     DX,AL                      ;Output the XOFF}
  302.   $C6/$06/>ASYNC_SEND_XOFF/$00/        {         MOV     BYTE [<Async_Send_XOFF],0  ;Turn off send XOFF flag}
  303.   $C6/$06/>ASYNC_XOFF_SENT/$01/        {         MOV     BYTE [<Async_XOFF_Sent],1  ;Turn on sent XOFF flag}
  304.   $E9/$B3/$FE/                         {         JMP     NEAR Poll                  ;Return}
  305.                                        {;}
  306.                                        {;  Not sending XOFF -- see if any character in buffer to be sent.}
  307.                                        {;}
  308.   $8B/$1E/>ASYNC_OBUFFER_TAIL/         {Int2d:   MOV     BX,[>Async_OBuffer_Tail]   ;Pick up output buffer pointers}
  309.   $3B/$1E/>ASYNC_OBUFFER_HEAD/         {         CMP     BX,[>Async_OBuffer_Head]}
  310.   $75/$0B/                             {         JNE     Int2m                      ;Skip if not equal --> something to send}
  311.                                        {;}
  312.                                        {;  If nothing to send, turn off write interrupts to avoid unnecessary}
  313.                                        {;  time spent handling useless THRE interrupts.}
  314.                                        {;}
  315.   $8B/$16/>ASYNC_UART_IER/             {Int2e:   MOV     DX,[>Async_Uart_IER]       ;If nothing -- or can't -- send ...}
  316.   $EC/                                 {         IN      AL,DX                      ;}
  317.   $24/$FD/                             {         AND     AL,$FD                     ;}
  318.   $EE/                                 {         OUT     DX,AL                      ;... disable write interrupts}
  319.   $E9/$9E/$FE/                         {         JMP     NEAR Poll                  ;}
  320.                                        {;}
  321.                                        {;  If something to send, ensure that remote system didn't send us XOFF.}
  322.                                        {;  If it did, we can't send anything, so turn off write interrupts and}
  323.                                        {;  wait for later (after an XON has been received).}
  324.                                        {;}
  325.   $F6/$06/>ASYNC_XOFF_RECEIVED/$01/    {Int2m:   TEST    BYTE [<Async_XOFF_Received],1 ;See if we received XOFF}
  326.   $75/$EE/                             {         JNZ     Int2e                      ;Yes -- can't send anything now}
  327.                                        {;}
  328.                                        {;  If we can send character, check DSR and CTS as requested.}
  329.                                        {;  If those status lines aren't ready, turn off write interrupts and}
  330.                                        {;  try later, after a line status change.}
  331.                                        {;}
  332.   $8B/$16/>ASYNC_UART_MSR/             {         MOV     DX,[>Async_Uart_MSR]       ;Otherwise get modem status}
  333.   $EC/                                 {         IN      AL,DX}
  334.   $A2/>ASYNC_MODEM_STATUS/             {         MOV     [>Async_Modem_Status],AL   ;and save modem status for later}
  335.                                        {;}
  336.   $F6/$06/>ASYNC_DO_DSR/$01/           {         TEST    BYTE [<Async_Do_DSR],1     ;See if DSR checking required}
  337.   $74/$04/                             {         JZ      Int2n                      ;No -- skip it}
  338.                                        {;}
  339.   $A8/<ASYNC_DSR/                      {         TEST    AL,<Async_DSR              ;Check for Data Set Ready}
  340.   $74/$DB/                             {         JZ      Int2e                      ;If not DSR, turn off write ints}
  341.                                        {;}
  342.   $F6/$06/>ASYNC_DO_CTS/$01/           {Int2n:   TEST    BYTE [<Async_Do_CTS],1     ;See if CTS checking required}
  343.   $74/$04/                             {         JZ      Int2o                      ;No -- skip it}
  344.                                        {;}
  345.   $A8/<ASYNC_CTS/                      {         TEST    AL,<Async_CTS              ;Check for Clear To Send}
  346.   $74/$D0/                             {         JZ      Int2e                      ;If not CTS, turn off write ints}
  347.                                        {;}
  348.                                        {;  Everything looks OK for sending, so send the character.}
  349.                                        {;}
  350.   $C4/$3E/>ASYNC_OBUFFER_PTR/          {Int2o:   LES     DI,[>Async_OBuffer_Ptr]    ;Get output buffer pointer}
  351.   $01/$DF/                             {         ADD     DI,BX                      ;Position to character to output}
  352.   $26/$8A/$05/                         {     ES: MOV     AL,[DI]                    ;Get character to output}
  353.   $8B/$16/>ASYNC_BASE/                 {         MOV     DX,[>Async_Base]           ;Get transmit hold register address}
  354.   $EE/                                 {         OUT     DX,AL                      ;Output the character}
  355.                                        {;}
  356.   $FF/$0E/>ASYNC_OBUFFER_USED/         {         DEC     WORD [>Async_OBuffer_Used] ;Decrement count of chars in buffer}
  357.   $43/                                 {         INC     BX                         ;Increment tail pointer}
  358.   $3B/$1E/>ASYNC_OBUFFER_SIZE/         {         CMP     BX,[>Async_OBuffer_Size]   ;See if past end of buffer}
  359.   $7E/$02/                             {         JLE     Int2z}
  360.   $31/$DB/                             {         XOR     BX,BX                      ;If so, wrap to front}
  361.                                        {;}
  362.   $89/$1E/>ASYNC_OBUFFER_TAIL/         {Int2z:   MOV     [>Async_OBuffer_Tail],BX   ;Store updated buffer tail}
  363.   $E9/$57/$FE/                         {         JMP     NEAR Poll}
  364.                                        {;}
  365.                                        {;  --- Line status change ---}
  366.                                        {;}
  367.   $3C/$06/                             {Int6:    CMP     AL,6                       ;Check for line status interrupt}
  368.   $75/$11/                             {         JNE     Int0                       ;No -- skip.}
  369.                                        {;}
  370.   $8B/$16/>ASYNC_UART_LSR/             {         MOV     DX,[>Async_Uart_LSR]       ;Yes -- pick up line status register}
  371.   $EC/                                 {         IN      AL,DX                      ;and its contents}
  372.   $24/$1E/                             {         AND     AL,$1E                     ;Strip unwanted bits}
  373.   $A2/>ASYNC_LINE_STATUS/              {         MOV     [>Async_Line_Status],AL    ;Store for future reference}
  374.   $08/$06/>ASYNC_LINE_ERROR_FLAGS/     {         OR      [>Async_Line_Error_Flags],AL ;Add to any past transgressions}
  375.                                        {;}
  376.   $E9/$42/$FE/                         {         JMP     NEAR Poll}
  377.                                        {;}
  378.                                        {;  --- Modem status change ---}
  379.                                        {;}
  380.   $3C/$00/                             {Int0:    CMP     AL,0                       ;Check for modem status change}
  381.   $74/$03/                             {         JE      Int0a                      ;Yes -- handle it}
  382.   $E9/$3B/$FE/                         {         JMP     NEAR Poll                  ;Else get next interrupt}
  383.                                        {;}
  384.   $8B/$16/>ASYNC_UART_MSR/             {Int0a:   MOV     DX,[>Async_Uart_MSR]       ;Pick up modem status reg. address}
  385.   $EC/                                 {         IN      AL,DX                      ;and its contents}
  386.   $A2/>ASYNC_MODEM_STATUS/             {         MOV     [>Async_Modem_Status],AL   ;Store for future reference}
  387.   $E8/$03/$00/                         {         CALL    EnabWI                     ;Turn on write interrupts, in case}
  388.                                        {;                                           ;status change resulted from CTS/DSR}
  389.                                        {;                                           ;changing state.}
  390.   $E9/$2D/$FE/                         {         JMP     NEAR Poll}
  391.                                        {;}
  392.                                        {;  Internal subroutine to enable write interrupts.}
  393.                                        {;}
  394.                                        {EnabWI: ;PROC    NEAR}
  395.   $8B/$16/>ASYNC_UART_IER/             {         MOV     DX,[>Async_Uart_IER]       ;Get interrupt enable register}
  396.   $EC/                                 {         IN      AL,DX                      ;Check contents of IER}
  397.   $A8/$02/                             {         TEST    AL,2                       ;See if write interrupt enabled}
  398.   $75/$03/                             {         JNZ     EnabRet                    ;Skip if so}
  399.   $0C/$02/                             {         OR      AL,2                       ;Else enable write interrupts ...}
  400.   $EE/                                 {         OUT     DX,AL                      ;... by rewriting IER contents}
  401.   $C3/                                 {EnabRet: RET                                ;Return to caller}
  402.                                        {;}
  403.                                        {;  Send non-specific EOI to 8259 controller.}
  404.                                        {;}
  405.   $B0/$20/                             {Back:    MOV     AL,$20                     ;EOI = $20}
  406.   $80/$3E/>ASYNC_IRQ/$08/              {         CMP     BYTE [>Async_Irq],8        ;Get IRQ level}
  407.   $72/$02/                             {         JB      Back2                      ;Only reset 1st 8259}
  408.                                        {;}
  409.   $E6/$A0/                             {         OUT     $A0,AL                     ;Reset second 8259}
  410.   $E6/$20);                            {Back2:   OUT     $20,AL                     ;Reset first 8259}
  411.  
  412. END;
  413.  
  414. (*----------------------------------------------------------------------*)
  415. (*               Async_Close --- Close down communications interrupts   *)
  416. (*----------------------------------------------------------------------*)
  417.  
  418. PROCEDURE Async_Close( Drop_DTR: BOOLEAN );
  419.  
  420. (*----------------------------------------------------------------------*)
  421. (*                                                                      *)
  422. (*     Procedure:  Async_Close                                          *)
  423. (*                                                                      *)
  424. (*     Purpose:    Resets interrupt system when UART interrupts         *)
  425. (*                 are no longer needed.                                *)
  426. (*                                                                      *)
  427. (*     Calling Sequence:                                                *)
  428. (*                                                                      *)
  429. (*        Async_Close( Drop_DTR : BOOLEAN );                            *)
  430. (*                                                                      *)
  431. (*           Drop_DTR --- TRUE to drop DTR when closing down port       *)
  432. (*                                                                      *)
  433. (*     Calls:  None                                                     *)
  434. (*                                                                      *)
  435. (*----------------------------------------------------------------------*)
  436.  
  437. VAR
  438.    I : INTEGER;
  439.    M : INTEGER;
  440.  
  441. BEGIN  (* Async_Close *)
  442.  
  443.    IF Async_Open_Flag THEN
  444.       BEGIN
  445.  
  446.          INLINE($FA);                 (* disable interrupts *)
  447.  
  448.                      (* Restore previous interrupt mask *)
  449.  
  450.          PORT[Async_IMR]        := Async_Save_IMR;
  451.  
  452.                      (* Restore previous baud rate *)
  453.  
  454.          PORT[ Async_Uart_LCR ] := $80;
  455.          PORT[ Async_Uart_THR ] := Async_Save_DLR;
  456.          PORT[ Async_Uart_IER ] := Async_Save_DHR;
  457.  
  458.                      (* Restore old 8250 interrupt status *)
  459.  
  460.          PORT[ Async_Uart_LCR ] := Async_Save_LCR AND $7F;
  461.          PORT[ Async_Uart_IER ] := Async_Save_IER;
  462.  
  463.                      (* Restore previous LCR *)
  464.  
  465.          PORT[ Async_Uart_LCR ] := Async_Save_LCR;
  466.  
  467.                      (* Restore previous MCR but possibly alter  *)
  468.                      (* DTR status.                              *)
  469.  
  470.          IF Drop_Dtr THEN
  471.             PORT[ Async_Uart_MCR ] := Async_Save_MCR AND $FE
  472.          ELSE
  473.             PORT[ Async_UART_MCR ] := Async_Save_MCR OR 1;
  474.  
  475.                      (* Restore the previous interrupt pointers *)
  476.  
  477.          SetIntVec( Async_Int , Async_Save_Iaddr );
  478.  
  479.          INLINE($FB);                 (* enable interrupts *)
  480.  
  481.                      (* re-initialize our data areas so we know *)
  482.                      (* the port is closed                      *)
  483.  
  484.          Async_Open_Flag := FALSE;
  485.          Async_XOFF_Sent := FALSE;
  486.          Async_Sender_On := FALSE;
  487.  
  488.       END;
  489.  
  490. END    (* Async_Close *);
  491.  
  492. (*----------------------------------------------------------------------*)
  493. (*    Async_Clear_Errors --- Reset pending errors in async port         *)
  494. (*----------------------------------------------------------------------*)
  495.  
  496. PROCEDURE Async_Clear_Errors;
  497.  
  498. (*----------------------------------------------------------------------*)
  499. (*                                                                      *)
  500. (*     Procedure:   Async_Clear_Errors                                  *)
  501. (*                                                                      *)
  502. (*     Purpose:     Resets pending errors in async port                 *)
  503. (*                                                                      *)
  504. (*     Calling sequence:                                                *)
  505. (*                                                                      *)
  506. (*        Async_Clear_Errors;                                           *)
  507. (*                                                                      *)
  508. (*     Calls:  None                                                     *)
  509. (*                                                                      *)
  510. (*----------------------------------------------------------------------*)
  511.  
  512. VAR
  513.    I:  INTEGER;
  514.    M:  INTEGER;
  515.  
  516. BEGIN (* Async_Clear_Errors *)
  517.  
  518.                    (* Read the RBR and reset any pending error conditions. *)
  519.                    (* First turn off the Divisor Access Latch Bit to allow *)
  520.                    (* access to RBR, etc.                                  *)
  521.  
  522.    INLINE($FA);  (* disable interrupts *)
  523.  
  524.    PORT[ Async_Uart_LCR ] := PORT[ Async_Uart_LCR ] AND $7F;
  525.  
  526.                    (* Read the Line Status Register to reset any errors *)
  527.                    (* it indicates                                      *)
  528.  
  529.    I := PORT[ Async_Uart_LSR ];
  530.  
  531.                    (* Read the Receiver Buffer Register in case it *)
  532.                    (* contains a character                         *)
  533.  
  534.    I := PORT[ Async_Uart_RBR ];
  535.  
  536.                    (* enable the irq on the 8259 controller *)
  537.  
  538.    I := PORT[ Async_IMR ];  (* get the interrupt mask register *)
  539.  
  540.    CASE Async_Irq OF
  541.       0..7 : M := 1 SHL Async_Irq;
  542.       8..15: M := 1 SHL ( Async_Irq - 8 );
  543.    END (* CASE *);
  544.  
  545.    M                 := M XOR $00FF;
  546.    PORT[ Async_IMR ] := I AND M;
  547.  
  548.                    (* enable OUT2 on 8250 *)
  549.  
  550.    I                      := PORT[ Async_Uart_MCR ];
  551.    PORT[ Async_Uart_MCR ] := I OR $0B;
  552.  
  553.                    (* enable the data ready interrupt on the 8250 *)
  554.  
  555.    PORT[ Async_Uart_IER ] := $0F;
  556.  
  557.                    (* Re-enable 8259 *)
  558.  
  559.    IF ( Async_Irq > 7 ) THEN
  560.       PORT[I8259_2] := $20;
  561.  
  562.    PORT[I8259_1]    := $20;
  563.  
  564.    INLINE($FB); (* enable interrupts *)
  565.  
  566. END   (* Async_Clear_Errors *);
  567.  
  568. (*----------------------------------------------------------------------*)
  569. (*    Async_Reset_Port --- Set/reset communications port parameters     *)
  570. (*----------------------------------------------------------------------*)
  571.  
  572. PROCEDURE Async_Reset_Port( ComPort       : INTEGER;
  573.                             BaudRate      : WORD;
  574.                             Parity        : CHAR;
  575.                             WordSize      : INTEGER;
  576.                             StopBits      : INTEGER );
  577.  
  578. (*----------------------------------------------------------------------*)
  579. (*                                                                      *)
  580. (*     Procedure:   Async_Reset_Port                                    *)
  581. (*                                                                      *)
  582. (*     Purpose:     Resets communications port                          *)
  583. (*                                                                      *)
  584. (*     Calling Sequence:                                                *)
  585. (*                                                                      *)
  586. (*        Async_Reset_Port(   ComPort       : INTEGER;                  *)
  587. (*                            BaudRate      : WORD;                     *)
  588. (*                            Parity        : CHAR;                     *)
  589. (*                            WordSize      : INTEGER;                  *)
  590. (*                            StopBits      : INTEGER);                 *)
  591. (*                                                                      *)
  592. (*           ComPort  --- which port (1, 2, 3, 4)                       *)
  593. (*           BaudRate --- Baud rate (110 to 57600)                      *)
  594. (*           Parity   --- "E" for even, "O" for odd, "N" for none,      *)
  595. (*                        "M" for mark, "S" for space.                  *)
  596. (*           WordSize --- Bits per character  (5 through 8)             *)
  597. (*           StopBits --- How many stop bits  (1 or 2)                  *)
  598. (*                                                                      *)
  599. (*     Calls:                                                           *)
  600. (*                                                                      *)
  601. (*        Async_Clear_Errors --- Clear async line errors                *)
  602. (*                                                                      *)
  603. (*----------------------------------------------------------------------*)
  604.  
  605. CONST   (* Baud Rate Constants *)
  606.  
  607.    Async_Num_Bauds = 11;
  608.  
  609.    Async_Baud_Table : ARRAY [1..Async_Num_Bauds] OF RECORD
  610.                                                        Baud, Bits : WORD;
  611.                                                     END
  612.  
  613.                     = ( ( Baud:  110;  Bits: $00 ),
  614.                         ( Baud:  150;  Bits: $20 ),
  615.                         ( Baud:  300;  Bits: $40 ),
  616.                         ( Baud:  600;  Bits: $60 ),
  617.                         ( Baud:  1200; Bits: $80 ),
  618.                         ( Baud:  2400; Bits: $A0 ),
  619.                         ( Baud:  4800; Bits: $C0 ),
  620.                         ( Baud:  9600; Bits: $E0 ),
  621.                         ( Baud: 19200; Bits: $E0 ),
  622.                         ( Baud: 38400; Bits: $E0 ),
  623.                         ( Baud: 57600; Bits: $E0 ) );
  624.  
  625. VAR
  626.    I       : INTEGER;
  627.    M       : INTEGER;
  628.    ComParm : INTEGER;
  629.  
  630. BEGIN (* Async_Reset_Port *)
  631.  
  632.             (*---------------------------------------------------*)
  633.             (*    Build the ComParm for RS232_Init               *)
  634.             (*    See Technical Reference Manual for description *)
  635.             (*---------------------------------------------------*)
  636.  
  637.                                    (* Set up the bits for the baud rate *)
  638.  
  639.    IF ( BaudRate > Async_Baud_Table[Async_Num_Bauds].Baud ) THEN
  640.       BaudRate := Async_Baud_Table[Async_Num_Bauds].Baud
  641.  
  642.    ELSE IF ( BaudRate < Async_Baud_Table[1].Baud ) THEN
  643.       BaudRate := Async_Baud_Table[1].Baud;
  644.  
  645.                                    (* Remember baud rate for purges *)
  646.    Async_Baud_Rate := BaudRate;
  647.  
  648.    I := 0;
  649.  
  650.    REPEAT
  651.       INC( I );
  652.    UNTIL ( ( I >= Async_Num_Bauds ) OR
  653.            ( BaudRate = Async_Baud_Table[I].Baud ) );
  654.  
  655.    ComParm := Async_Baud_Table[I].Bits;
  656.  
  657.                                    (* Choose Parity.  Temporarily   *)
  658.                                    (* consider mark, space as none. *)
  659.    Parity := UpCase( Parity );
  660.  
  661.    CASE Parity OF
  662.       'E' : ComParm := ComParm OR $0018;
  663.       'O' : ComParm := ComParm OR $0008;
  664.       ELSE ;
  665.    END (* CASE *);
  666.                                    (* Choose number of data bits *)
  667.  
  668.    WordSize := WordSize - 5;
  669.  
  670.    IF ( WordSize < 0 ) OR ( WordSize > 3 ) THEN
  671.       WordSize := 3;
  672.  
  673.    ComParm := ComParm OR WordSize;
  674.  
  675.                                    (* Choose stop bits *)
  676.  
  677.    IF StopBits = 2 THEN
  678.       ComParm := ComParm OR $0004;  (* default is 1 stop bit *)
  679.  
  680.                                    (* Use the BIOS COM port init routine *)
  681.  
  682.    BIOS_RS232_Init( ComPort - 1 , ComParm );
  683.  
  684.                                    (* If > 9600 baud, we have to screw *)
  685.                                    (* around a bit                     *)
  686.  
  687.    IF ( BaudRate >= 19200 ) THEN
  688.       BEGIN
  689.  
  690.          I                      := PORT[ Async_Uart_LCR ];
  691.          PORT[ Async_Uart_LCR ] := I OR $80;
  692.  
  693.          PORT[ Async_Uart_THR ] := 115200 DIV BaudRate;
  694.          PORT[ Async_Uart_IER ] := 0;
  695.  
  696.          I                      := PORT[ Async_Uart_LCR ];
  697.          PORT[ Async_Uart_LCR ] := I AND $7F;
  698.  
  699.       END;
  700.                                    (* Now fix up mark, space parity *)
  701.  
  702.    IF ( ( Parity = 'M' ) OR ( Parity = 'S' ) ) THEN
  703.       BEGIN
  704.  
  705.          I                      := PORT[ Async_Uart_LCR ];
  706.          PORT[ Async_Uart_LCR ] := $80;
  707.  
  708.          ComParm := WordSize OR ( ( StopBits - 1 ) SHL 2 );
  709.  
  710.          CASE Parity OF
  711.             'M' : ComParm := ComParm OR $0028;
  712.             'S' : ComParm := ComParm OR $0038;
  713.             ELSE ;
  714.          END (* CASE *);
  715.  
  716.          PORT[ Async_Uart_LCR ] := ComParm;
  717.  
  718.       END;
  719.                                    (* Sender is enabled *)
  720.    Async_Sender_On := TRUE;
  721.                                    (* Clear any pending errors on *)
  722.                                    (* async line                  *)
  723.    Async_Clear_Errors;
  724.  
  725. END   (* Async_Reset_Port *);
  726.  
  727. (*----------------------------------------------------------------------*)
  728. (*               Async_Open --- Open communications port                *)
  729. (*----------------------------------------------------------------------*)
  730.  
  731. FUNCTION Async_Open( ComPort       : INTEGER;
  732.                      BaudRate      : WORD;
  733.                      Parity        : CHAR;
  734.                      WordSize      : INTEGER;
  735.                      StopBits      : INTEGER  ) : BOOLEAN;
  736.  
  737. (*----------------------------------------------------------------------*)
  738. (*                                                                      *)
  739. (*     Function:   Async_Open                                           *)
  740. (*                                                                      *)
  741. (*     Purpose:    Opens communications port                            *)
  742. (*                                                                      *)
  743. (*     Calling Sequence:                                                *)
  744. (*                                                                      *)
  745. (*        Flag := Async_Open( ComPort       : INTEGER;                  *)
  746. (*                            BaudRate      : WORD;                     *)
  747. (*                            Parity        : CHAR;                     *)
  748. (*                            WordSize      : INTEGER;                  *)
  749. (*                            StopBits      : INTEGER) : BOOLEAN;       *)
  750. (*                                                                      *)
  751. (*           ComPort  --- which port (1 though 4)                       *)
  752. (*           BaudRate --- Baud rate (110 to 57600)                      *)
  753. (*           Parity   --- "E" for even, "O" for odd, "N" for none,      *)
  754. (*                        "S" for space, "M" for mark.                  *)
  755. (*           WordSize --- Bits per character  (5 through 8)             *)
  756. (*           StopBits --- How many stop bits  (1 or 2)                  *)
  757. (*                                                                      *)
  758. (*           Flag returned TRUE if port initialized successfully;       *)
  759. (*           Flag returned FALSE if any errors.                         *)
  760. (*                                                                      *)
  761. (*     Calls:                                                           *)
  762. (*                                                                      *)
  763. (*        Async_Reset_Port --- initialize RS232 port                    *)
  764. (*        Async_Close      --- close open RS232 port                    *)
  765. (*        SetIntVec        --- set address of RS232 interrupt routine   *)
  766. (*        GetIntVec        --- get address of RS232 interrupt routine   *)
  767. (*                                                                      *)
  768. (*----------------------------------------------------------------------*)
  769.  
  770. VAR
  771.    M : BYTE;
  772.  
  773. BEGIN  (* Async_Open *)
  774.                              (* If port open, close it down first.  *)
  775.    IF Async_Open_Flag THEN
  776.       Async_Close( FALSE );
  777.                              (* Choose communications port *)
  778.  
  779.    IF ( ComPort < 1 ) THEN
  780.       ComPort := 1
  781.    ELSE IF ( ComPort > MaxComPorts ) THEN
  782.       ComPort := MaxComPorts;
  783.  
  784.    Async_Port  := ComPort;
  785.    Async_Base  := Com_Base [ ComPort ];
  786.    Async_Irq   := Com_Irq  [ ComPort ];
  787.    Async_Int   := Com_Int  [ ComPort ];
  788.  
  789.                                    (* Set register pointers for ISR routine *)
  790.  
  791.    Async_Uart_IER  := Async_Base + UART_IER;
  792.    Async_Uart_IIR  := Async_Base + UART_IIR;
  793.    Async_Uart_MSR  := Async_Base + UART_MSR;
  794.    Async_Uart_LSR  := Async_Base + UART_LSR;
  795.    Async_Uart_MCR  := Async_Base + UART_MCR;
  796.    Async_Uart_THR  := Async_Base + UART_THR;
  797.    Async_Uart_LCR  := Async_Base + UART_LCR;
  798.  
  799.                                    (* Check if given port installed *)
  800.  
  801.    IF ( PORT[ Async_Uart_IIR ] AND $00F8 ) <> 0 THEN
  802.       Async_Open := FALSE          (* Serial port not installed *)
  803.    ELSE
  804.       BEGIN   (* Open the port *)
  805.  
  806.                                    (* Check if interrupts currently     *)
  807.                                    (* enabled on this port, and if so,  *)
  808.                                    (* disable them.                     *)
  809.          CASE Async_Irq OF
  810.             0..7 : BEGIN
  811.                       Async_IMR := I8088_IMR1;
  812.                       M         := 1 SHL Async_Irq;
  813.                    END;
  814.             8..15: BEGIN
  815.                       Async_IMR := I8088_IMR2;
  816.                       M         := 1 SHL ( Async_Irq - 8 );
  817.                    END;
  818.          END (* CASE *);
  819.  
  820.          Async_Save_IMR  := PORT[Async_IMR];
  821.          PORT[Async_IMR] := Async_Save_IMR OR M;
  822.  
  823.                                    (* Save current serial port settings *)
  824.  
  825.          Async_Save_LCR := PORT[ Async_Uart_LCR ];
  826.          Async_Save_MCR := PORT[ Async_Uart_MCR ];
  827.          Async_Save_IER := PORT[ Async_Uart_IER ];
  828.  
  829.          PORT[ Async_Uart_LCR ] := $80;
  830.          Async_Save_DLR         := PORT[ Async_Uart_THR ];
  831.          Async_Save_DHR         := PORT[ Async_Uart_IER ];
  832.  
  833.                                    (* Get current interrupt address     *)
  834.  
  835.          GetIntVec( Async_Int , Async_Save_Iaddr );
  836.          GetIntVec( $03, Set_Reboot_Vector);
  837.          GetIntVec( $19, Get_Reboot_Vec);
  838.          setintvec( $03, @Get_Reboot_Vec);
  839.  
  840.                                    (* Set new interrupt routine address *)
  841.  
  842.          SetIntVec( Async_Int , @Async_Isr );
  843.  
  844.                                    (* Set up UART                   *)
  845.  
  846.          Async_Reset_Port( ComPort, BaudRate, Parity, WordSize, StopBits );
  847.  
  848.                                    (* Remember that port is open *)
  849.          Async_Open      := TRUE;
  850.          Async_Open_Flag := TRUE;
  851.  
  852.     END;
  853.  
  854. END   (* Async_Open *);
  855.  
  856.